package ch.ethz.fcl.metrobuzz.data.long_term_trajectory.node;

import java.awt.Color;
import java.text.DecimalFormat;
import java.util.List;

import javax.vecmath.Vector2d;

import org.lwjgl.opengl.GL11;

import ch.ethz.fcl.metrobuzz.data.MBData;
import ch.ethz.fcl.metrobuzz.data.WeightedAverage;
import ch.ethz.fcl.metrobuzz.data.long_term_trajectory.node.LTTNode;
import ch.ethz.fcl.metrobuzz.render.techniques.colors.ColorTable;
import ch.ethz.fcl.metrobuzz.render.techniques.projection.Projection;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Point2D;
import ch.ethz.fcl.metrobuzz.spatialindex.object2d.Rectangle;
import ch.ethz.fcl.metrobuzz.tools.MBGL;
import ch.ethz.fcl.metrobuzz.tools.MBTools;
import ch.ethz.fcl.metrofont.MetroFont;
import ch.ethz.fcl.metrofont.Pen;

/**
 * display the information of the association node: average travel distance,
 * time; dep and arr nodes sorted by their number;
 * 
 * @author Zeng Wei
 * @email zeng@arch.ethz.ch
 * 
 */
public class LTTNodeInfoBoard {
	private MBData data;
	private LTTNode an;

	private Rectangle board;
	private Rectangle boardOutLine;

	private MetroFont font;

	public LTTNodeInfoBoard(LTTNode an) {
		this.an = an;
		this.data = an.getData();
		font = new MetroFont();
		font.setFontColor(Color.WHITE);
	}

	/**
	 * two diagonal points of the rectangle
	 * 
	 * @param p1
	 * @param p2
	 */
	public void setBoard(Point2D p1, Point2D p2) {
		this.board = new Rectangle(p1, p2);
	}

	public void render(Projection proj) {
		renderBackground(proj);
		displayInfo();
		renderStatistics();
	}

	private void renderBackground(Projection proj) {
		// one pixel distance
		float onePixelLength = proj.getWorldDistance(1);

		float minX = board.getMinX() - onePixelLength;
		float maxX = board.getMaxX() + onePixelLength;
		float minY = board.getMinY() - onePixelLength;
		float maxY = board.getMaxY() + onePixelLength;
		boardOutLine = new Rectangle(minX, minY, maxX, maxY);

		GL11.glColor3f(0, 215.0f / 255, 59.0f / 255); // green
		board.render(GL11.GL_POLYGON);

		GL11.glLineWidth(3.0f);
		ColorTable.assignColor(ColorTable.BLACK, 1.0f);
		boardOutLine.render();

		GL11.glLineWidth(2);
		ColorTable.assignColor(ColorTable.YELLOW, 1.0f);
		boardOutLine.render();
	}

	private void displayInfo() {
		GL11.glColor3f(1, 1, 1);
		float fontSize = board.getHeight() / 20;

		List<AssociationEnd> depEndList = an.getDepEndList();
		List<AssociationEnd> arrEndList = an.getArrEndList();
		WeightedAverage aveDura = an.getAveDura();
		WeightedAverage aveDist = an.getAveDist();

		int tripSize = 0;
		for (AssociationEnd end : depEndList)
			tripSize += end.getFrequency();
		for (AssociationEnd end : arrEndList)
			tripSize += end.getFrequency();

		Pen pen = new Pen(board.getMinX() + fontSize, board.getMaxY()
				- fontSize * 2, 0, 0, 0, fontSize);
		font.display("trips: " + String.format("%,8d%n", tripSize), pen);
		pen = new Pen(board.getMinX() + 11 * fontSize, board.getMaxY()
				- fontSize * 2, 0, 0, 0, fontSize);
		font.display(
				"duration: "
						+ MBTools.formatTimeInSeconds(aveDura.getAverage()),
				pen);
		pen = new Pen(board.getMinX() + 20 * fontSize, board.getMaxY()
				- fontSize * 2, 0, 0, 0, fontSize);

		DecimalFormat myFormatter = new DecimalFormat("###,###.##");
		font.display(
				"distance (km): "
						+ myFormatter.format(aveDist.getAverage() / 1000), pen);
	}

	// render sorted departing and arriving stations and its statistics
	private void renderStatistics() {
		List<AssociationEnd> depEndList = an.getDepEndList();
		List<AssociationEnd> arrEndList = an.getArrEndList();

		int maxFreq = Math.max(depEndList.get(0).getFrequency(), arrEndList
				.get(0).getFrequency());

		GL11.glColor3f(1, 1, 1);
		float fontSize = board.getHeight() / 20;
		Pen pen = new Pen(board.getMinX() + fontSize, board.getMaxY()
				- fontSize * 3.5f, 0, 0, 0, fontSize);
		font.display("Departure stations:\n", pen);

		pen = new Pen(board.getMinX() + fontSize, board.getMaxY() - fontSize
				* 12, 0, 0, 0, fontSize);
		font.display("Arriving stations:\n", pen);

		GL11.glLineWidth(1.0f);
		ColorTable.assignColor(ColorTable.BLACK, 1.0f);

		Point2D line1Start = new Point2D(board.getMinX() + fontSize,
				board.getMaxY() - fontSize * 10.5f);
		Point2D line1End = new Point2D(board.getMaxX() - fontSize,
				board.getMaxY() - fontSize * 10.5f);

		renderStatistics(depEndList, line1Start, line1End, maxFreq,
				fontSize * 6.2f);

		Point2D line2Start = new Point2D(board.getMinX() + fontSize,
				board.getMaxY() - fontSize * 19f);
		Point2D line2End = new Point2D(board.getMaxX() - fontSize,
				board.getMaxY() - fontSize * 19f);

		renderStatistics(arrEndList, line2Start, line2End, maxFreq,
				fontSize * 6.2f);
	}

	private void renderStatistics(List<AssociationEnd> endList, Point2D startP,
			Point2D endP, int maxValue, float maxHeight) {
		GL11.glLineWidth(1.0f);

		int size = Math.min(endList.size(), 5);
		Vector2d yDir = new Vector2d(0, 1);
		for (int i = 0; i < size; i++) {
			Point2D barStart = startP.getPointAt(endP, i * 1.0f / size + 1.0f
					/ (4 * size));
			Point2D barEnd = startP.getPointAt(endP, i * 1.0f / size + 1.0f * 3
					/ (4 * size));
			float height = endList.get(i).getFrequency() * maxHeight / maxValue;
			Point2D barStartTop = barStart.getPointAt(yDir, height);
			Rectangle bar = new Rectangle(barStartTop, barEnd);

			GL11.glColor3f(1.0f, 1.0f, 1.0f);
			bar.render(GL11.GL_POLYGON);

			ColorTable.assignColor(ColorTable.BLACK, 1.0f);
			bar.render();

			float fontSize = bar.getWidth() / 5;

			float x = bar.getMinX() + bar.getWidth() / 2;
			float y = bar.getMaxY();

			String nodeId = data.getScene()
					.getNode(endList.get(i).getEndNodeIndex()).getId();
			x -= font.getLength(nodeId, fontSize) / 2;
			Pen pen = new Pen(x, y, 0, 0, 0, fontSize);
			font.display(nodeId, pen);

			String freq = endList.get(i).getFrequency() + "";
			x = bar.getMinX() + bar.getWidth() / 2
					- font.getLength(freq, fontSize) / 2;
			y = bar.getMaxY() - fontSize;
			pen = new Pen(x, y, 0, 0, 0, fontSize);
			font.display(freq, pen);
		}

		ColorTable.assignColor(ColorTable.BLACK, 1.0f);
		GL11.glBegin(GL11.GL_LINES);
		MBGL.render(startP);
		MBGL.render(endP);
		GL11.glEnd();
	}

	public LTTNode getAssociationNode() {
		return an;
	}
}
